package com.siwei.mes.sync.tc.service;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.siwei.mes.common.util.DateHelper;
import com.siwei.mes.common.util.JsonUtils;
import com.siwei.mes.entity.experiment.*;
import com.siwei.mes.entity.materials.Materials;
import com.siwei.mes.entity.sync.tc.SupplyTask;
import com.siwei.mes.entity.sync.tc.Waybill;
import com.siwei.mes.enums.*;
import com.siwei.mes.mapper.experiment.CheckBatchConfigMapper;
import com.siwei.mes.mapper.experiment.ExperimentBatchRecordMapper;
import com.siwei.mes.mapper.experiment.ExperimentCheckWaybillMapper;
import com.siwei.mes.mapper.experiment.ExperimentGenConfigMapper;
import com.siwei.mes.mapper.syncTc.SupplyTaskMapper;
import com.siwei.mes.service.experiment.ExperimentCheckWaybillWeekService;
import com.siwei.mes.service.materials.MaterialsService;
import com.siwei.mes.service.system.SystemParamService;
import com.siwei.mes.sync.tc.entity.GenMaterialResult;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 生成原材料批检
 *
 * @Description: 生成原材料批检
 * @Version: 1.0
 * @author: mlchen
 * @date: 2025/3/8 00:55
 */
@Service
public class GenMaterialBatchExperimentService extends GenMaterialAbstractService {
    private static final Logger log = LoggerFactory.getLogger("tc");

    /**
     * 是否是快检
     */
    private final boolean IS_QUICK = false;

    /**
     * 检测类型
     */
    private final Integer CHECK_TYPE = CheckEnum.BATCH.getCode();

    @Resource
    private ExperimentGenConfigMapper experimentGenConfigMapper;
    @Resource
    private SupplyTaskMapper supplyTaskMapper;
    @Resource
    private CheckBatchConfigMapper checkBatchConfigMapper;
    @Resource
    private ExperimentCheckWaybillMapper experimentCheckWaybillMapper;
    @Resource
    private ExperimentBatchRecordMapper experimentBatchRecordMapper;
    @Resource
    private MaterialsService materialsService;
    @Resource
    private ExperimentCheckWaybillWeekService experimentCheckWaybillWeekService;
    @Resource
    private SystemParamService systemParamService;

    /**
     * 生成批检试验委托
     *
     * @param mesType 砼材类型
     * @param entity  运单信息
     */
    public GenMaterialResult genExperiment(TcContrastExperimentTypeEnum mesType, Waybill entity) {
        GenMaterialResult genMaterialResult = new GenMaterialResult();
        genMaterialResult.setIsSuccess(true);
        genMaterialResult.setCheckType(CheckEnum.BATCH.getCode());

        log.info("开始生成【{}】批检！", mesType.getName());
        log.info("运单id：【{}】运单编号：【{}】状态：【{}】，开始执行生成原材料批检记录", entity.getWaybillId(), entity.getWaybillCode(), entity.getState());
        ExperimentGenConfig genConfig = experimentGenConfigMapper.getConfig(mesType.getMesType(), CheckEnum.BATCH.getCode());

        if (genConfig == null) {
            log.info("【{}】生成委托规则配置为空，暂不生成批检！", mesType.getName());
            genMaterialResult.setErrorMsg("生成委托规则配置为空").setIsSuccess(false);
            return genMaterialResult;
        }
        if (genConfig.getIsOpen() == null || genConfig.getIsOpen() == 0) {
            log.info("【{}】生成【{}】委托规则配置暂未开启，暂不生成！", mesType.getName(), CheckEnum.BATCH.getName());
            genMaterialResult.setErrorMsg("委托规则配置暂未开启").setIsSuccess(false);
            return genMaterialResult;
        }
        if (!WaybillStateEnum.DONE.getCode().equals(entity.getState())) {
            log.info("运单id：【{}】运单编号：【{}】状态：【{}】 状态不为已完成，暂不生成批检！", entity.getWaybillId(), entity.getWaybillCode(), entity.getState());
            genMaterialResult.setErrorMsg("状态不为已完成").setIsSuccess(false);
            return genMaterialResult;
        }


        SupplyTask supplyTask = supplyTaskMapper.selectByTaskId(entity.getSupplyTaskId());
        if (supplyTask == null) {
            log.info("【{}】生成委托不存在供货任务，暂不生成！", mesType.getName());
            genMaterialResult.setErrorMsg("生成委托不存在供货任务").setIsSuccess(false);
            return genMaterialResult;
        }


        Materials materials = materialsService.checkIsExist(mesType.getMesType(), entity.getProjectName(), entity.getProjectSpecs());
        if (materials.getSpecId() == null) {
            log.info("【{}】【{}】【{}】生成委托不存在对应材料，暂不生成批检！", mesType.getName(), materials.getMaterialName(), materials.getMaterialSpecs());
            genMaterialResult.setErrorMsg("生成委托不存在对应材料").setIsSuccess(false);
            return genMaterialResult;
        }

        double signQuantity = this.getDoubleValue(entity.getSignQuantity());//签收方量
        double genQuantity = this.getDoubleValue(entity.getGenBatchQuantity());//已生成批检委托方量
        /**这里直接判断 签收的方量是否等于已生成对应类型的委托的方量*/
        if (signQuantity == genQuantity) {
            log.info("运单id：【{}】运单编号：【{}】没有剩余方量可以生成批检试验台账，暂不生成批检！签收方量：【{}】，已生成批检委托数量：【{}】", entity.getWaybillId(), entity.getWaybillCode(), signQuantity, genQuantity);
            genMaterialResult.setErrorMsg("没有剩余方量可以生成批检试验台账，暂不生成批检！").setIsSuccess(false);
            return genMaterialResult;
        }
        if (genQuantity > signQuantity) {
            log.info("运单id：【{}】运单编号：【{}】剩余方量大于签收方量，暂不生成批检！签收方量：【{}】，已生成批检委托数量：【{}】", entity.getWaybillId(), entity.getWaybillCode(), signQuantity, genQuantity);
            genMaterialResult.setErrorMsg("剩余方量大于签收方量，暂不生成批检！").setIsSuccess(false);
            return genMaterialResult;
        }


        log.info("运单签收方量：【{}】,已生成批检委托数量：【{}】，剩余方量：【{}】", signQuantity, genQuantity, signQuantity - genQuantity);
        /**这里判断剩余方量*/
        signQuantity = signQuantity - genQuantity;


        Integer checkRules = genConfig.getCheckRules();//规则 1-车车都检  2-按重量  3-按车数  4-按时间
        String checkThreshold = genConfig.getCheckThreshold() == null ? "0" : genConfig.getCheckThreshold();//阈值  多少吨或者多少天  根据规则来走的
        Integer qualifiedType = genConfig.getQualifiedType();//限定类型  1-同一厂家（同一配合比）   2-同一批次（同一任务单）
        log.info("批检生成【{}】规则为：【{}】,阈值为：【{}】，限定类型：【{}】", mesType.getName(), checkRules, checkThreshold, qualifiedType);


        /**委托试验名称*/
        Set<String> entrustExperimentSet = new HashSet<>();
        /**试验项目code集合*/
        Set<String> testProjectCodeList = new HashSet<>();
        /**获取所有批检配置信息*/
        List<CheckBatchConfig> checkBatchConfigList = checkBatchConfigMapper.getList(new CheckBatchConfig().setIsDel(0).setProjectCategory(mesType.getMesType()));


        /**这里排除不符合条件的，只保存需要的*/
        List<CheckBatchConfig> batchConfigList = new ArrayList<>();

        for (CheckBatchConfig batchConfig : checkBatchConfigList) {
            /**放入试验项目code集合*/
            List<String> codeList = Arrays.asList(batchConfig.getTestProjectCode().split(","));
            /**放入委托试验名称*/
            List<String> nameList = Arrays.asList(batchConfig.getTestProjectName().split(","));
            if (!batchConfig.getCheckType().equals(CheckTypeEnum.DEFAULT_CHECK.getCode())) {
                /**判断是否将试验项目添加到实验委托中*/
                if (super.isAddExperimentByCheckType(batchConfig.getCheckType(), batchConfig.getTestProjectCode(), materials)) {
                    log.info("检测类型：【{}】，试验项目code：【{}】，试验项目【{}】不添加到实验委托中，已存在有委托！",
                            batchConfig.getCheckType(), batchConfig.getTestProjectCode(), batchConfig.getTestProjectName());
                    continue;
                }
            }
            testProjectCodeList.addAll(codeList);
            entrustExperimentSet.addAll(nameList);
            batchConfigList.add(batchConfig);
        }

        log.info("生成批检最终的试验项目code集合：【{}】，委托试验名称集合：【{}】", testProjectCodeList, entrustExperimentSet);


        /**这里判断一下是否需要拆分运单生成规则  生成规则是 按重量 并且运单数量大于阈值数量 目前只有外加剂的需要拆分*/
        List<Integer> splitTypeList = new ArrayList<>();
        splitTypeList.add(MaterialsEnum.ADMIXTURE.getCode());
        splitTypeList.add(MaterialsEnum.FINE.getCode());
        splitTypeList.add(MaterialsEnum.COARSE.getCode());
        splitTypeList.add(MaterialsEnum.CEMENT.getCode());
        if (checkRules == 2 && splitTypeList.contains(mesType.getMesType())) {
            double configThreshold = this.getDoubleValue(new BigDecimal(checkThreshold));//配置的阈值
            if (signQuantity > configThreshold) {
                log.info("需要拆分【{}】批检运单！", mesType.getName());
                Set<Long> experimentIdList = this.genBatchExperimentSplit(mesType, entity, supplyTask, materials, configThreshold, qualifiedType, batchConfigList);
                log.info("批检【{}】，拆分运单逻辑生成完毕。对应试验委托id:【{}】", mesType.getName(), experimentIdList);

                genMaterialResult.setIsSplit(true);
                genMaterialResult.setExperimentIdList(new ArrayList<>(experimentIdList));
                return genMaterialResult;
            }
        }

        /**这里直接执行按时间的逻辑*/
        if (checkRules == 4) {
            log.info("需要按时间生成【{}】批检！", mesType.getName());
            Set<Long> experimentIdList = this.genBatchExperimentByTime(mesType, entity, supplyTask, materials, checkThreshold, qualifiedType, batchConfigList);
            log.info("批检【{}】，按时间逻辑生成完毕。对应试验委托id:【{}】", mesType.getName(), experimentIdList);

            genMaterialResult.setIsSplit(true);
            genMaterialResult.setExperimentIdList(new ArrayList<>(experimentIdList));
            return genMaterialResult;
        }


        /**这里判断批检 创建原材料台账*/
        Long experimentId = null;// 试验台账id

        if (checkRules == 1) {//1-车车都检
            log.info("这里是车车都检不需要处理");
        } else if (checkRules == 2 || checkRules == 3) {//2-按重量  3-按车数
            /**查询对应批检检是否有之前的台账关联关系  这里只取第一个的id就行了*/
            ExperimentCheckWaybill checkWaybill = new ExperimentCheckWaybill().setCheckType(CheckEnum.BATCH.getCode())
                    .setMaterialName(materials.getMaterialName()).setMaterialSpecs(materials.getMaterialSpecs()).setExperimentType(mesType.getTcType());
            if (qualifiedType != null && qualifiedType == 1) {//1-同一厂家
                checkWaybill.setFactory(entity.getFactory());
            } else if (qualifiedType != null && qualifiedType == 2) {//2-同一供应商(没有这个概念)
                checkWaybill.setSupplyCompanyCompany(entity.getSupplyCompanyCompany());
            }
            log.info("批检查询对应批检检是否有之前的台账关联关系，查询条件：【{}】", JSON.toJSONString(checkWaybill));
            List<ExperimentCheckWaybill> checkList = experimentCheckWaybillMapper.getList(checkWaybill);
            if (CollectionUtil.isNotEmpty(checkList)) {
                double totalThreshold = 0;// 之前的条数或者是方量
                double addTotal = 0;// 本次加上之前的条数或者方量

                if (checkRules == 3) {//3-按车数 就是运单的条数
                    totalThreshold = checkList.size();
                    addTotal = totalThreshold + 1;
                    log.info("批检【按车数】生成，当前车数：【{}】,需要添加车数：【{}】，最终车数：【{}】", totalThreshold, 1, addTotal);
                } else {
                    totalThreshold = checkList.get(0).getBehalfNumber();
                    addTotal = totalThreshold + signQuantity;
                    log.info("批检【按重量】生成，当前重量：【{}】，运单生产方量：【{}】，最终方量：【{}】", totalThreshold, signQuantity, addTotal);
                }

                log.info("判断是否清理试验委托和运单之间的关系表，最终方量：【{}】，阈值方量：【{}】", addTotal, checkThreshold);
                /**如果之前的加上本次的 大于阈值需要生产一个新的试验台账记录否则就用之前的*/

                if (addTotal == Double.parseDouble(checkThreshold)) {
                    experimentId = checkList.get(0).getExperimentId();
                } else if (addTotal > Double.parseDouble(checkThreshold)) {//如果大于阈值
                    /**判断是否塞满原材料相关阈值配置的*/
                    String systemParamValue = systemParamService.selectBySystemCode(SystemParamEnum.IS_CLOGGING_MATERIALS_THRESHOLD, "0");
                    if (StringUtils.isNotBlank(systemParamValue) && "1".equals(systemParamValue)) {
                        log.info("系统参数：【{}】是否塞满原材料相关阈值配置的，已开启，直接塞满最后一个委托然后再生成一个新的委托！", SystemParamEnum.IS_CLOGGING_MATERIALS_THRESHOLD);

                        log.info("这里需要给之前的阈值补齐剩余的数量，补齐之后再生成一个新的数量");
                        double residueNumber = Double.parseDouble(checkThreshold) - totalThreshold;
                        signQuantity = signQuantity - residueNumber;
                        log.info("配置阈值：【{}】，上一个委托总数量：【{}】，上一个试验委托还剩下数量：【{}】，补齐之后剩余：【{}】", checkThreshold, totalThreshold, residueNumber, signQuantity);

                        Long beforeExperimentId = checkList.get(0).getExperimentId();//上一个试验委托的id

                        /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
                        super.handleExperimentRelations(beforeExperimentId, entity.getId(), supplyTask.getId(), residueNumber, IS_QUICK);
                    }

                    log.info("如果之前的加上本次的大于阈值需要生产一个新的试验台账记录，开始清空experimentCheckWaybill表数据");
                    for (ExperimentCheckWaybill checkWaybillInfo : checkList) {
                        experimentCheckWaybillMapper.deleteByPrimaryKey(checkWaybillInfo.getId());
                    }
                } else {
                    if (!checkList.isEmpty()) {
                        experimentId = checkList.get(0).getExperimentId();
                        log.info("试验委托和运单之间的关系表不为空，直接取第一条的试验委托，委托id：【{}】", experimentId);
                    } else {
                        log.info("试验委托和运单之间的关系表为空，需要重新生成试验委托！");
                    }
                }
            }
        }

        /**如果试验台账id为空 就需要生成一个新的  如果有就只要加对应的子表记录 共用之前的试验台账记录*/
        if (experimentId == null) {
            String entrustExperiment = null;
            if (!entrustExperimentSet.isEmpty()) {
                entrustExperiment = entrustExperimentSet.stream().map(String::valueOf).collect(Collectors.joining(","));
            }

            /**新增原材料试验台账*/
            Experiment experiment = super.createExperimentInfoByWaybillInfo(mesType, CHECK_TYPE, entity, supplyTask, materials, signQuantity, entrustExperiment, testProjectCodeList);
            /**这里赋值对应的试验台账信息*/
            experimentId = experiment.getId();

            /**新增试验台账对应批检配置记录*/
            for (CheckBatchConfig batchConfig : batchConfigList) {
                experimentBatchRecordMapper.insertSelective(new ExperimentBatchRecord().tcInit(true).setExperimentId(experimentId).setBatchId(batchConfig.getId()));

                /**快检/批检与试验台账和运单关联的关系*/
                ExperimentCheckWaybill checkInfo = new ExperimentCheckWaybill()
                        .setCheckId(batchConfig.getId()).setFactory(entity.getFactory()).setSupplyTaskCode(supplyTask.getSupplyTaskCode())
                        .setCheckType(CheckEnum.BATCH.getCode()).setCreateTime(new Date()).setWaybillId(entity.getId()).setSupplyCompanyCompany(entity.getSupplyCompanyCompany())
                        .setExperimentId(experimentId);

                experimentCheckWaybillMapper.insertSelective(checkInfo);
            }
        }
        /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
        super.handleExperimentRelations(experimentId, entity.getId(), supplyTask.getId(), signQuantity, IS_QUICK);

        log.info("批检【{}】，生成完毕。对应试验委托id:【{}】", mesType.getName(), experimentId);
        genMaterialResult.setExperimentIdList(Collections.singletonList(experimentId));
        return genMaterialResult;
    }

    /**
     * 设置星期五   所有关系都清空了
     * 来一车 500
     * 生成1-4的运单  A500
     * 5   B 500
     * 6  B 500
     * <p>
     * 星期日的晚上23点59分59秒  截断的时候 还要判断  567这三天有没有委托  如果没有就要生成
     * <p>
     * 每一个运单 都需要判断  设置的是周五 判断周五之前是否有委托  如果没有就要生成  如果有直接跳过
     * <p>
     * 如果之前的没有  就是当前运单的数量
     * <p>
     * 如果之后的没有  就是之前的委托（之前的委托是10000吨   那生成的就是10000吨）的 代表数量
     * <p>
     * 本周 是按照自然周  星期一到星期日  星期日就结束了
     * <p>
     * 设置星期一
     * 1  来500
     * A 500
     * B 500  最后全部加在B里面
     * <p>
     * 设置星期二
     * 1   A委托
     * 2-7  B委托
     * 根据时间生成委托
     *
     * @param mesType         砼材类型
     * @param entity          运单
     * @param supplyTask      供货任务
     * @param materials       物料
     * @param checkThreshold  配置的周几
     * @param qualifiedType   限定类型  1-同一厂家（同一配合比）   2-同一批次（同一任务单）
     * @param batchConfigList 批检配置
     * @return
     */
    private Set<Long> genBatchExperimentByTime(TcContrastExperimentTypeEnum mesType, Waybill entity, SupplyTask supplyTask,
                                               Materials materials, String checkThreshold, Integer qualifiedType,
                                               List<CheckBatchConfig> batchConfigList) {
        Set<Long> experimentIdList = new HashSet<>();
        log.info("开始处理【{}】批检，只有按时间的才生成委托！", mesType.getName());
        String weekNumber = DateHelper.getWeekNumber(new Date());
        WeekEnum weekEnum = WeekEnum.selectByCode(weekNumber);
        if (weekEnum == null) {
            log.info("当前时间没有对应的周几！直接跳过！");
            return experimentIdList;
        }
        log.info("当前时间是【{}】,对应的周几：【{}】", DateHelper.getCurrentDate(), weekEnum.getName());

        /**委托试验名称*/
        Set<String> entrustExperimentSet = new HashSet<>();
        /**试验项目code集合*/
        Set<String> testProjectCodeList = new HashSet<>();
        if (batchConfigList.isEmpty()) {
            log.info("【{}】批检配置为空，不生成直接跳过！", mesType.getName());
            return experimentIdList;
        }

        for (CheckBatchConfig batchConfig : batchConfigList) {
            /**放入试验项目code集合*/
            List<String> codeList = Arrays.asList(batchConfig.getTestProjectCode().split(","));
            /**放入委托试验名称*/
            List<String> nameList = Arrays.asList(batchConfig.getTestProjectName().split(","));
            testProjectCodeList.addAll(codeList);
            entrustExperimentSet.addAll(nameList);
        }

        String entrustExperiment = null;
        if (!entrustExperimentSet.isEmpty()) {
            entrustExperiment = entrustExperimentSet.stream().map(String::valueOf).collect(Collectors.joining(","));
        }
        /**获取批检对应的数据*/
        ExperimentCheckWaybillWeek selectWaybillWeekInfo = new ExperimentCheckWaybillWeek();
        selectWaybillWeekInfo.setCheckType(CheckEnum.BATCH.getCode());
        selectWaybillWeekInfo.setExperimentType(mesType.getMesType());
        selectWaybillWeekInfo.setProjectName(materials.getMaterialName());
        selectWaybillWeekInfo.setProjectSpec(materials.getMaterialSpecs());

        if (qualifiedType != null && qualifiedType == 1) {//1-同一厂家
            selectWaybillWeekInfo.setFactory(entity.getFactory());
        } else if (qualifiedType != null && qualifiedType == 2) {//2-同一供应商
            selectWaybillWeekInfo.setSupplyCompanyCompany(entity.getSupplyCompanyCompany());
        }
        log.info("查询到按时间的生产的对应关系表记录信息，查询条件：【{}】", JsonUtils.getJson(selectWaybillWeekInfo));
        ExperimentCheckWaybillWeek waybillWeekConfig = experimentCheckWaybillWeekService.getConfig(selectWaybillWeekInfo);
        log.info("查询到按时间的生产的对应关系表记录信息：【{}】", JsonUtils.getJson(waybillWeekConfig));
        int nowWeekNumber = Integer.parseInt(weekNumber);//当前周几
        int checkWeekNumber = Integer.parseInt(checkThreshold);//阈值配置的周几

        log.info("当前周几：【{}】，阈值配置的周几：【{}】", nowWeekNumber, checkWeekNumber);

        double signQuantity = this.getDoubleValue(entity.getSignQuantity());
        double genQuantity = this.getDoubleValue(entity.getGenBatchQuantity());

        log.info("按时间逻辑运单签收方量：【{}】,已生成批检委托数量：【{}】，剩余方量：【{}】", signQuantity, genQuantity, signQuantity - genQuantity);
        /**这里判断剩余方量*/
        signQuantity = signQuantity - genQuantity;

        if (checkWeekNumber == 1 && waybillWeekConfig.getFirstExperimentId() == null) {
            log.info("这里配置是周一，需要直接生成第一个试验委托");
            Long experimentId = this.createExperimentAndUpdateConfig(mesType, entity, supplyTask, materials,
                    signQuantity, entrustExperiment, testProjectCodeList, waybillWeekConfig, true);
            /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
            super.handleExperimentRelations(experimentId, entity.getId(), supplyTask.getId(), signQuantity, IS_QUICK);
            experimentIdList.add(experimentId);
        }

        if (checkWeekNumber >= nowWeekNumber) {
            log.info("这里配置的周几大于当前周几，不需要生成试验委托,直接保存关联关系");
            Long experimentId = waybillWeekConfig.getFirstExperimentId();
            if (experimentId == null) {
                experimentId = this.createExperimentAndUpdateConfig(mesType, entity, supplyTask, materials,
                        signQuantity, entrustExperiment, testProjectCodeList, waybillWeekConfig, true);
            }
            /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
            super.handleExperimentRelations(experimentId, entity.getId(), supplyTask.getId(), signQuantity, IS_QUICK);
            experimentIdList.add(experimentId);
        } else {
            /**这里需要判断是否有第一条试验委托 如果没有需要创建*/
            log.info("这里配置的周几小于等于当前周几，需要判断是否有第一条试验委托 如果没有需要创建");
            Long firstExperimentId = waybillWeekConfig.getFirstExperimentId();
            if (firstExperimentId == null) {
                Long experimentId = this.createExperimentAndUpdateConfig(mesType, entity, supplyTask, materials,
                        signQuantity, entrustExperiment, testProjectCodeList, waybillWeekConfig, true);
                /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
                super.handleExperimentRelations(experimentId, entity.getId(), supplyTask.getId(), signQuantity, IS_QUICK);
                experimentIdList.add(experimentId);
            }

            log.info("这里配置的周几小于等于当前周几，需要判断是否有第二条试验委托 如果没有需要创建");
            Long experimentId = waybillWeekConfig.getSecondExperimentId();
            if (experimentId == null) {
                experimentId = this.createExperimentAndUpdateConfig(mesType, entity, supplyTask, materials,
                        signQuantity, entrustExperiment, testProjectCodeList, waybillWeekConfig, false);
            }
            /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
            super.handleExperimentRelations(experimentId, entity.getId(), supplyTask.getId(), signQuantity, IS_QUICK);
            experimentIdList.add(experimentId);
        }

        log.info("批检【{}】，按时间处理委托完毕。对应试验委托id:【{}】", mesType.getName(), experimentIdList);
        return experimentIdList;
    }

    /**
     * 创建试验委托并修改周配置表
     *
     * @param mesType             砼材类型
     * @param entity              运单
     * @param supplyTask          供货任务
     * @param materials           物料
     * @param behalfNumber        代表数量
     * @param entrustExperiment   委托试验名称
     * @param testProjectCodeList 试验项目code集合
     * @param waybillWeekConfig   周配置信息
     * @param isFirst             是否是第一个委托
     * @return
     */
    private Long createExperimentAndUpdateConfig(TcContrastExperimentTypeEnum mesType, Waybill entity, SupplyTask supplyTask,
                                                 Materials materials, double behalfNumber, String entrustExperiment, Set<String> testProjectCodeList,
                                                 ExperimentCheckWaybillWeek waybillWeekConfig, boolean isFirst) {
        Experiment experiment = super.createExperimentInfoByWaybillInfo(mesType, CHECK_TYPE, entity, supplyTask, materials, behalfNumber, entrustExperiment, testProjectCodeList);
        Long experimentId = experiment.getId();

        if (isFirst) {
            waybillWeekConfig.setFirstExperimentId(experimentId);
        } else {
            waybillWeekConfig.setSecondExperimentId(experimentId);
        }
        experimentCheckWaybillWeekService.update(waybillWeekConfig);

        return experimentId;
    }


    /**
     * 根据运单数量拆分多个试验委托   这里只处理常规类型的 批检配置
     *
     * @param mesType         砼材类型
     * @param entity          运单
     * @param supplyTask      供货任务
     * @param materials       物料
     * @param configThreshold 配置的阈值
     * @param qualifiedType   限定类型  1-同一厂家（同一配合比）   2-同一批次（同一任务单）
     * @param batchConfigList 批检配置
     */
    private Set<Long> genBatchExperimentSplit(TcContrastExperimentTypeEnum mesType, Waybill entity, SupplyTask supplyTask,
                                              Materials materials, double configThreshold, Integer qualifiedType,
                                              List<CheckBatchConfig> batchConfigList) {
        Set<Long> experimentIdList = new HashSet<>();
        log.info("开始处理【{}】批检，只有按重量的才拆分成多个运单！", mesType.getName());
        double signQuantity = this.getDoubleValue(entity.getSignQuantity());
        double genQuantity = this.getDoubleValue(entity.getGenBatchQuantity());


        log.info("拆分逻辑运单签收方量：【{}】,已生成批检委托数量：【{}】，剩余方量：【{}】", signQuantity, genQuantity, signQuantity - genQuantity);
        /**这里判断剩余方量*/
        signQuantity = signQuantity - genQuantity;

        log.info("正在执行【{}】拆分运单逻辑，总签收数量：【{}】,配置阈值数量：【{}】", mesType.getName(), signQuantity, configThreshold);


        /**试验项目code集合*/
        Set<String> testProjectCodeList = new HashSet<>();
        if (batchConfigList.isEmpty()) {
            log.info("【{}】批检配置为空，不生成直接跳过！", mesType.getName());
            return experimentIdList;
        }

        /**第一步  先判断之前最后一个委托 还可以塞多少的阈值*/
        /**这里去配置的第一条  如果有一条的数据 那之后的数据都会有的  因为都是统一清理的*/
        /**查询对应批检检是否有之前的台账关联关系*/
        ExperimentCheckWaybill checkWaybill = new ExperimentCheckWaybill().setCheckType(CheckEnum.BATCH.getCode())
                .setMaterialName(materials.getMaterialName()).setMaterialSpecs(materials.getMaterialSpecs()).setExperimentType(mesType.getTcType());
        if (qualifiedType != null && qualifiedType == 1) {//1-同一厂家
            checkWaybill.setFactory(entity.getFactory());
        } else if (qualifiedType != null && qualifiedType == 2) {//2-同一供应商(没有这个概念)
            checkWaybill.setSupplyCompanyCompany(entity.getSupplyCompanyCompany());
        }

        /**第一次生成的数量*/
        double firstGenThreshold = 0;//第一次可以生成的数量
        log.info("genBatchExperimentSplit方法查询对应批检检是否有之前的台账关联关系，查询条件：【{}】", JSON.toJSONString(checkWaybill));
        List<ExperimentCheckWaybill> checkList = experimentCheckWaybillMapper.getList(checkWaybill);
        if (!checkList.isEmpty()) {
            Long experimentId = checkList.get(0).getExperimentId();
            experimentIdList.add(experimentId);
            double totalThreshold = checkList.get(0).getBehalfNumber();
            firstGenThreshold = configThreshold - totalThreshold;//可以生成的数量

            log.info("拆分逻辑。【{}】批检生成，阈值重量：【{}】，当前重量：【{}】,第一次可生成的数量：【{}】", configThreshold, mesType.getName(), totalThreshold, firstGenThreshold);

            if (firstGenThreshold > 0) {
                log.info("拆分逻辑。【{}】批检生成，第一次可生成的数量大于0，开始生成！", mesType.getName());

                List<CheckBatchConfig> batchConfigs = this.getBatchConfigListTwo(batchConfigList, materials);
                for (CheckBatchConfig batchConfig : batchConfigs) {
                    /**放入试验项目code集合*/
                    List<String> codeList = Arrays.asList(batchConfig.getTestProjectCode().split(","));
                    /**放入委托试验名称*/
                    List<String> nameList = Arrays.asList(batchConfig.getTestProjectName().split(","));
                    testProjectCodeList.addAll(codeList);
                }

                /**新增试验台账对应批检配置记录*/
                for (CheckBatchConfig batchConfig : batchConfigs) {
                    experimentBatchRecordMapper.insertSelective(new ExperimentBatchRecord().tcInit(true).setExperimentId(experimentId).setBatchId(batchConfig.getId()));
                }
                /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
                super.handleExperimentRelations(experimentId, entity.getId(), supplyTask.getId(), firstGenThreshold, IS_QUICK);

                log.info("开始清空experimentCheckWaybill表数据,第一次拆分的时候已给此试验委托塞满。直接清空！experimentId：【{}】", experimentId);
                experimentCheckWaybillMapper.deleteByExperimentId(experimentId);
            }
        }

        /**第二步  处理第一次拆分之后 总数量-拆分数量=剩余的数量  大于阈值的数量*/
        signQuantity = signQuantity - firstGenThreshold;//剩余的数量
        log.info("第二次拆分的代表数量：【{}】，第一次拆分的数量：【{}】", signQuantity, firstGenThreshold);
        double needNum = Math.floor(signQuantity / configThreshold);//需要生成对应阈值的次数

        /**定义对应的阈值数组*/
        List<Double> thresholdList = new ArrayList<>();
        for (int i = 0; i < needNum; i++) {
            thresholdList.add(configThreshold);
        }

        log.info("第二次生成需要拆分的运单整个数：【{}】,对应代表数量：【{}】", needNum, thresholdList);
        /**委托试验名称*/
        Set<String> entrustExperimentSet = new HashSet<>();
        for (CheckBatchConfig batchConfig : batchConfigList) {
            /**放入试验项目code集合*/
            List<String> codeList = Arrays.asList(batchConfig.getTestProjectCode().split(","));
            /**放入委托试验名称*/
            List<String> nameList = Arrays.asList(batchConfig.getTestProjectName().split(","));
            testProjectCodeList.addAll(codeList);
            entrustExperimentSet.addAll(nameList);
        }

        String entrustExperiment = null;
        if (!entrustExperimentSet.isEmpty()) {
            entrustExperiment = entrustExperimentSet.stream().map(String::valueOf).collect(Collectors.joining(","));
        }


        for (int i = 0; i < needNum; i++) {
            List<CheckBatchConfig> batchConfigs = this.getBatchConfigListTwo(batchConfigList, materials);
            for (CheckBatchConfig batchConfig : batchConfigs) {
                /**放入试验项目code集合*/
                List<String> codeList = Arrays.asList(batchConfig.getTestProjectCode().split(","));
                /**放入委托试验名称*/
                List<String> nameList = Arrays.asList(batchConfig.getTestProjectName().split(","));
                testProjectCodeList.addAll(codeList);
                entrustExperimentSet.addAll(nameList);
            }
            /**新增混凝土试验台账*/
            Experiment experiment = super.createExperimentInfoByWaybillInfo(mesType, CHECK_TYPE, entity, supplyTask, materials, thresholdList.get(i), entrustExperiment, testProjectCodeList);

            /**这里赋值对应的试验台账信息*/
            Long experimentId = experiment.getId();

            /**新增试验台账对应批检配置记录*/
            for (CheckBatchConfig batchConfig : batchConfigs) {
                experimentBatchRecordMapper.insertSelective(new ExperimentBatchRecord().tcInit(true).setExperimentId(experimentId).setBatchId(batchConfig.getId()));
            }
            /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
            super.handleExperimentRelations(experimentId, entity.getId(), supplyTask.getId(), thresholdList.get(i), IS_QUICK);

            experimentIdList.add(experimentId);
        }

        /**执行剩余数量的逻辑  需要添加查询之前的委托数量  直接加到阈值最大*/
        log.info("判断批检【{}】，是否需要执行第三次剩余数量的逻辑!", mesType.getName());
        double modThreshold = signQuantity % configThreshold;//第二次拆分的代表数量/阈值数量 取余数
        if (modThreshold > 0) {
            log.info("开始处理第三次拆分数量的逻辑，剩余数量：【{}】,最后一次！这次只需要生成一个新的委托的逻辑！", modThreshold);

            List<CheckBatchConfig> batchConfigs = this.getBatchConfigListTwo(batchConfigList, materials);
            for (CheckBatchConfig batchConfig : batchConfigs) {
                /**放入试验项目code集合*/
                List<String> codeList = Arrays.asList(batchConfig.getTestProjectCode().split(","));
                /**放入委托试验名称*/
                List<String> nameList = Arrays.asList(batchConfig.getTestProjectName().split(","));
                testProjectCodeList.addAll(codeList);
                entrustExperimentSet.addAll(nameList);
            }
            /**新增原材料试验台账*/
            Experiment experiment = super.createExperimentInfoByWaybillInfo(mesType, CHECK_TYPE, entity, supplyTask, materials, modThreshold, entrustExperiment, testProjectCodeList);

            /**这里赋值对应的试验台账信息*/
            Long experimentId = experiment.getId();


            /**判断是否塞满原材料相关阈值配置的*/
            String systemParamValue = systemParamService.selectBySystemCode(SystemParamEnum.IS_CLOGGING_MATERIALS_THRESHOLD, "0");

            /**新增试验台账对应批检配置记录*/
            for (CheckBatchConfig batchConfig : batchConfigs) {
                experimentBatchRecordMapper.insertSelective(new ExperimentBatchRecord().tcInit(true).setExperimentId(experimentId).setBatchId(batchConfig.getId()));

                /**这里判断是否给之前的补齐*/
                if (StringUtils.isNotBlank(systemParamValue) && "1".equals(systemParamValue)) {
                    log.info("系统参数：【{}】是否塞满原材料相关阈值配置的，已开启，需要添加对应拆分逻辑的关联关系！", SystemParamEnum.IS_CLOGGING_MATERIALS_THRESHOLD);

                    log.info("这里需要给之前的阈值补齐剩余的数量，补齐之后再生成一个新的数量，对应关联关系需要添加进去！");
                    /**快检/批检与试验台账和运单关联的关系*/
                    ExperimentCheckWaybill checkInfo = new ExperimentCheckWaybill()
                            .setCheckId(batchConfig.getId()).setFactory(entity.getFactory()).setSupplyTaskCode(supplyTask.getSupplyTaskCode())
                            .setCheckType(CheckEnum.BATCH.getCode()).setCreateTime(new Date()).setWaybillId(entity.getId()).setSupplyCompanyCompany(entity.getSupplyCompanyCompany())
                            .setExperimentId(experimentId);

                    experimentCheckWaybillMapper.insertSelective(checkInfo);
                }
            }
            /**试验委托和运单关系、试验委托和供货任务关系、修改运单状态*/
            super.handleExperimentRelations(experimentId, entity.getId(), supplyTask.getId(), modThreshold, IS_QUICK);
            experimentIdList.add(experimentId);
        }

        log.info("批检【{}】，拆分完毕。对应试验委托id:【{}】", mesType.getName(), experimentIdList);
        return experimentIdList;
    }

    /**
     * 第二次判断需要操作的试验项目
     *
     * @param batchConfigList
     * @param materials
     * @return
     */
    private List<CheckBatchConfig> getBatchConfigListTwo(List<CheckBatchConfig> batchConfigList, Materials materials) {
        log.info("开始第二次校验是否需要添加试验项目到试验委托中！");
        List<CheckBatchConfig> list = new ArrayList<>();
        for (CheckBatchConfig batchConfig : batchConfigList) {
            if (!batchConfig.getCheckType().equals(CheckTypeEnum.DEFAULT_CHECK.getCode())) {
                /**判断是否将试验项目添加到实验委托中*/
                if (super.isAddExperimentByCheckType(batchConfig.getCheckType(), batchConfig.getTestProjectCode(), materials)) {
                    log.info("检测类型：【{}】，试验项目code：【{}】，试验项目【{}】不添加到实验委托中，已存在有委托！",
                            batchConfig.getCheckType(), batchConfig.getTestProjectCode(), batchConfig.getTestProjectName());
                    continue;
                }
            }
            list.add(batchConfig);
        }
        return list;
    }
}
